<template>
  <div class="smart-image-wrapper" :style="wrapperStyle">
    <el-image
      v-bind="attrs"
      :src="optimizedSrc"
      :fit="fit"
      :lazy="lazy"
      :preview-src-list="preview ? [realSrc] : []"
      @load="handleLoad"
      @error="handleError"
    >
      <template #placeholder>
        <div
          class="flex items-center justify-center h-full text-gray-400 text-sm"
        >
          加载中...
        </div>
      </template>
      <template #error>
        <div
          class="flex items-center justify-center h-full text-red-400 text-sm"
        >
          加载失败
        </div>
      </template>
    </el-image>
  </div>
</template>

<script lang="ts" setup>
import { ref, computed, useAttrs, onMounted } from "vue";

interface Props {
  src: string;
  lazy?: boolean;
  preview?: boolean;
  fit?: "fill" | "contain" | "cover" | "none" | "scale-down";
  width?: string | number;
  height?: string | number;
  compress?: boolean;
  quality?: number;
  fallback?: string;
}

const props = withDefaults(defineProps<Props>(), {
  lazy: true,
  preview: false,
  fit: "cover",
  compress: true,
  quality: 0.7,
  fallback: "/default-image.png"
});

const attrs = useAttrs();
const realSrc = ref("");
const optimizedSrc = ref("");
const loaded = ref(false);

const wrapperStyle = computed(() => ({
  width: typeof props.width === "number" ? `${props.width}px` : props.width,
  height: typeof props.height === "number" ? `${props.height}px` : props.height,
  overflow: "hidden",
  display: "inline-block"
}));

/**
 * 修正本地路径，兼容 @/assets 或相对路径
 */
function resolveSrcPath(src: string): string {
  if (/^https?:\/\//.test(src)) return src;
  try {
    // 若为 Vite 项目中的本地资源
    return new URL(src, import.meta.url).href;
  } catch {
    return src;
  }
}

/**
 * 压缩本地大图（浏览器端）
 */
async function compressLocalImage(src: string): Promise<string> {
  if (!props.compress) return src;
  try {
    const blob = await fetch(src).then(r => {
      if (!r.ok) throw new Error("无法加载图片");
      return r.blob();
    });
    const bitmap = await createImageBitmap(blob);
    const canvas = document.createElement("canvas");
    const maxWidth = 800;
    const scale = Math.min(1, maxWidth / bitmap.width);
    canvas.width = bitmap.width * scale;
    canvas.height = bitmap.height * scale;
    const ctx = canvas.getContext("2d")!;
    ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
    return canvas.toDataURL("image/jpeg", props.quality);
  } catch (err) {
    console.warn("[SmartImage] 图片压缩失败:", err);
    return src;
  }
}

async function initImage() {
  const path = resolveSrcPath(props.src);
  realSrc.value = path;
  optimizedSrc.value = path;

  if (!/^https?:\/\//.test(path) && props.compress) {
    const result = await compressLocalImage(path);
    optimizedSrc.value = result;
  }
}

function handleLoad() {
  loaded.value = true;
}

function handleError() {
  console.warn("[SmartImage] 加载失败，使用 fallback");
  optimizedSrc.value = props.fallback;
}

onMounted(() => {
  initImage();
});
</script>

<style scoped>
.smart-image-wrapper {
  position: relative;
  border-radius: 0.5rem;
  background-color: #f6f6f6;
}
</style>
